package javabasic.slipch.calendarseeker;
import java.lang.Comparable;
import javabasic.slipch.calendarseeker.Month;

public final class Date implements Comparable<Date> {

	public Date( int year, int month, int day) {
		YEAR = year;
		MONTH = Month.getMonth(year, month);
		DAY = day;
	}
	
	public static int dayDistance(final Date from, final Date to) {
		assert from.compareTo(to) <= 0;
		int yearsCount = to.getYear() - from.getYear();
		
		// 1) same year
		if (yearsCount == 0) {
			int yearDaysCount = YEAR_DAYS_COUNT + (to.getYear() % 4 == 0 ? 1 : 0);
			return from.daysTillEndOfYear() + to.daysFromBeginingOfYear() - yearDaysCount;
		}
		
		// 2) consecutive years
		if(yearsCount == 1) {
			return from.daysTillEndOfYear() + to.daysFromBeginingOfYear();
		}
		
		//now yearsCount is the count of years between "from" and "to" dates excluding "to" and "from" years
		yearsCount--;
		
		assert yearsCount >= 1;
		
		int leapCount = (yearsCount / 4) + ( ( ( 4 - ( (from.getYear() + 1)  % 4 ) % 4 ) < ( yearsCount % 4 ) ) ? 1 : 0 );
		
		int yearsDaysDist = yearsCount * YEAR_DAYS_COUNT + leapCount;
		
		return yearsDaysDist + from.daysTillEndOfYear() + to.daysFromBeginingOfYear();
	}
	
	public int compareTo(final Date o) {
		if (getYear() < o.getYear()) {
			return -1;
		} else if( getYear() > o.getYear() ) {
			return 1;
		} else if (getMonth().getNumber() < o.getMonth().getNumber()) {
			return -1;
		} else if( getMonth().getNumber() > o.getMonth().getNumber()) {
			return 1;
		} else if(getDay() < o.getDay()) {
			return -1;
		} else if (getDay() > o.getDay()){
			return 1;
		} else {
			return 0;
		}
	}
	
	public int getYear() {
		return YEAR;
	}
	
	public final Month getMonth() {
		return MONTH;
	}
	
	public int getDay() {
		return DAY;
	}
	
	public int daysTillEndOfYear() {
		int daysTillendOftheMonth = getMonth().getDaysCount() - getDay();//exclude this day
		if (getMonth() == Month.last()) {
			return daysTillendOftheMonth;
		}
		
		int result = 0;
		Month m = getMonth();
		do {
			m = m.next(getYear());//skip this month
			result += m.getDaysCount();
			
		} while (m != Month.last());
		
		result += daysTillendOftheMonth;
		return result;
	}
	
	public int daysFromBeginingOfYear() { //include this day
		
		if (getMonth() == Month.first()) {
			return getDay();
		}
		
		int result = 0;
		Month m = getMonth();
		do {
			m = m.previous(getYear());//skip this month
			result += m.getDaysCount();
		} while (m != Month.first());
		
		result += getDay();
		return result;
	}
	
	private final int YEAR;
	private final Month MONTH;
	private final int DAY;
	private final static int YEAR_DAYS_COUNT = 365;
};